package CoteServeur;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.JOptionPane;

import com.sun.servicetag.SystemEnvironment;




public class ControleurServeur implements Serializable {

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Attributs pour le serveur
	
	//Attributs pour la "base de données"
	private HashMap<String, CompteLocuteur> comptes;
	
	transient private HashMap<String, Socket> dicoSock;
	transient private Vector< Socket > vecSocket;
	
	private String TypeCmd;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	private static final long serialVersionUID = 1L;
	
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Controleur, Getters, Setters
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	public ControleurServeur(){
		setComptes(new HashMap<String, CompteLocuteur>());
	}
	public void lancerServ(){
		try {
			dicoSock = new HashMap<String, Socket>();
			vecSocket = new Vector<Socket>();
			ServerSocket ss;
			Socket socket;
			ss = new ServerSocket(2015);
			//System.out.println("le Serveur est à l'ecoute du port " + ss.getLocalPort());
		
            while(true){
                 
            socket = ss.accept();
			vecSocket.add(socket);
//            //System.out.println("Un Client veut se connecter");
    		Thread t =  new Thread(new Authentification(socket, this));
    		t.start();
            }
        } catch (IOException e) {           
            System.err.println("Erreur serveur");
        }
//            catch (IOException e) {
//			e.printStackTrace();
//		}
		
        /*try {
			ss.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
        
        try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}*/
		sauve();
	}
	public HashMap<String, CompteLocuteur> getComptes() {
		return comptes;
	}

	public void setComptes(HashMap<String, CompteLocuteur> comptes) {
		this.comptes = comptes;
	}
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Fonctions principales
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public void inscrireUtilisateur(String infos, Socket socket){
		String infosDec[] = decoupe(infos);
		//0 = nom de compte
		//1 = organisme
		//2 = intitulé de langue
		//3 = niveau de langue
		//4 = mot de passe
//		//System.out.println("affichage donné du compte : ----------------------------------");
		PrintWriter out = null;
		try {
			out = new PrintWriter(socket.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		if (comptes.get(infosDec[0]) == null) {
			Langue l = new Langue(infosDec[2],infosDec[3]);
			
			CompteLocuteur cL = new CompteLocuteur(infosDec[0], infosDec[4], infosDec[1], l);
			
			comptes.put(infosDec[0], cL);

			
//			//System.out.println("Fin d'affichage ------------------------------------------");
			
			Thread t = new Thread(new Emission(out, "validation inscription", "dial",this));
			t.start();
			
			sauve();
			
			//connecterUtilisateur();
	}
	else {
		Thread t = new Thread(new Emission(out, "Nom de compte déjà utilisé", "dial",this));
		t.start();
	}
	  

  }
	//////////////////////////////////////////
	public void validerConnexion(String ch, Socket socket){
		PrintWriter out = null;
		try {
			out = new PrintWriter(socket.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
//		//System.out.println("Socket infos : " + socket);
		String[] chaine = this.decoupe(ch);
//		//System.out.println("login Reçu : " + chaine[0] + " mdp Reçu : " + chaine[1]);
			
		if(getComptes().get(chaine[0]) != null){
			CompteLocuteur compte = getComptes().get(chaine[0]);
			if(getComptes().get(chaine[0]).getMotDePasse().equals(chaine[1])) {
				compte.setStatut(CompteLocuteur.DISPONIBLE);


				//getVecSock().put(chaine[0], socket);


//				//System.out.println("--en ligne--");

				Thread t = new Thread(new Emission(out, chaine[0]+"&°&"+compte.getType()+"&°&"+compte.getStatut(), "valConec",this));/*&°&"+getComptes().get(chaine[0])*/
				t.start();	
			}
			else {
				Thread t = new Thread(new Emission(out, "Login invalide", "dial",this));
				t.start();
			}
		}
		else {
			Thread t = new Thread(new Emission(out, "Login invalide", "dial",this));
			t.start();
		}		

	}
		
	public void deconnexion(String message, Socket socket) {
		if(comptes.containsKey(message)){
			PrintWriter out = null;
			CompteLocuteur compte = comptes.get(message);
			compte.setStatut(2);
			
			try {
				out = new PrintWriter(socket.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			Thread t = new Thread(new Emission(out, "Deconnexion réussie", "deco",this));
			t.start();	
		}
	}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public void addContact(String message, Socket socket) {
//		//System.out.println("tentative d'ajout de contact, verification en cours ..............");
		PrintWriter out = null;
		String[] chaine = this.decoupe(message);
		if(comptes.containsKey(chaine[1])){
			if(!comptes.get(chaine[0]).getVecContact().contains(chaine[1])){
				
				Vector<String> vec = comptes.get(chaine[0]).getVecContact();
				vec.add(chaine[1]);
				comptes.get(chaine[0]).setVecContact(vec);
				sauve();
//				//System.out.println("la liste des amis : " + vec);
				try {
					out = new PrintWriter(socket.getOutputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}
//				if(comptes.get(chaine[1]).getStatut() == 0) {
//					chaine[1] = "+ " + chaine[1];
//				}
//				else if(comptes.get(chaine[1]).getStatut() == 1) {
//					chaine[1] = "# " + chaine[1];
//				}
//				else
//					chaine[1] = "- " + chaine[1];
				Thread t = new Thread(new Emission(out, chaine[0], "addCont",this));	
				t.start();
			}	
			else{
				try {
					out = new PrintWriter(socket.getOutputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}
				Thread t = new Thread(new Emission(out, "Deja ajouté", "dial",this));
				t.start();	
			}
		}		
		else
		{
			try {
				out = new PrintWriter(socket.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			Thread t = new Thread(new Emission(out, "Ce profil n'existe pas", "dial",this));
			t.start();		
		}
	}
	
	public void infContact(String message, Socket socket) {
//		//System.out.println("........Tentative de récuperation des infos d'un contact........");
		PrintWriter out = null;
		if(comptes.containsKey(message)) {
			CompteLocuteur compte = comptes.get(message);
			try {
				out = new PrintWriter(socket.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			Thread t = new Thread(new Emission(out, compte.getNomCompte() + "&°&" + compte.getOrganisme() + "&°&" + compte.getStatut(), "infCont",this));	
			t.start();
		}
	}
	
	public void actuCont(String message, Socket socket) {
//		//System.out.println("........Tentative d'actualisation des contacts........");
		PrintWriter out = null;
		if(comptes.containsKey(message)) {
			CompteLocuteur compte = comptes.get(message);
			try {
				out = new PrintWriter(socket.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			Thread t = new Thread(new Emission(out, compte.getNomCompte(), "actuCont",this));	
			t.start();
		}
	}

	public void modifMdp(String message, Socket socket) {
		
//		//System.out.println("........Tentative de changement de mot de passe........");
		PrintWriter out = null;
		String[] ch = decoupe(message);
		if(comptes.containsKey(ch[0])) {
			CompteLocuteur compte = comptes.get(ch[0]);
			if(compte.getMotDePasse().equals(ch[1])) {
				compte.setMotDePasse(ch[2]);
				sauve();
				try {
					out = new PrintWriter(socket.getOutputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}
				Thread t = new Thread(new Emission(out, "Mot de passe modifié", "modifMdp",this));	
				t.start();
				}
			else {
				{
					try {
						out = new PrintWriter(socket.getOutputStream());
					} catch (IOException e) {
						e.printStackTrace();
					}
					Thread t = new Thread(new Emission(out, "Mot de passe incorrect", "dial",this));
					t.start();		
				}
			}
		}
	}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Fonctions pratiques
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public String[] decoupe(String chaineADecoupe){
		return chaineADecoupe.split("&°&");
	}

	public String getTypeCmd() {
		return TypeCmd;
	}

	public void setTypeCmd(String typeCmd) {
		TypeCmd = typeCmd;
	}
	

	private void sauve() {
		try {
			FileOutputStream f = new FileOutputStream("Fsauve.ser");
			ObjectOutputStream out = new ObjectOutputStream(f);
			out.writeObject(this);
			//System.out.println("La sauvegarde a réussie");
		} catch (NotSerializableException e) {
			//System.out.println("Un objet n'est pas sérialisable.");
		}
		  catch (FileNotFoundException e) {
			//System.out.println("Fichier non encore crée. (sauve)");
		} catch (NullPointerException e) {
			//System.out.println("Ecriture nulle (sauve)");
		} catch (IOException e) {
			//System.out.println("Problème à l'écriture (sauve)");
		}
	}


	public ControleurServeur restaure() {
		try {
			FileInputStream fichier = new FileInputStream("Fsauve.ser");
			ObjectInputStream in = new ObjectInputStream(fichier);
//			//System.out.println("La restauration a réussie");
			return ((ControleurServeur) in.readObject());
		} catch (FileNotFoundException e) {
			//System.out.println("Fichier non encore crée. (restaure)");
			FileOutputStream f;
				try {
					f = new FileOutputStream("Fsauve.ser");
					ObjectOutputStream out = new ObjectOutputStream(f);
					out.close();
					f.close();
					} catch (IOException e1) {
					//System.out.println("Création échouée (restaure)");
				}

			return this;
		} catch (NullPointerException e) {
			//System.out.println("Ecriture nulle (restaure)");
			
			return this;
		} catch (IOException e) {
			//System.out.println("Problème à la lecture (restaure)");
			
			return this;
		} catch(ClassNotFoundException e) {
			//System.out.println("Classe non trouvée (restaure)");
			
			return this;
		}
		
	}
	public void envoieMess(String message, Socket socket) {
		String[] messdec = this.decoupe(message);
		String profilEnvoyeur = messdec[0];
		String profilRec = messdec[1];
		String mess = messdec[2];

	//	getVecSock().put(profilEnvoyeur, socket);
		try {
			//System.out.println("affichage info ------------------------------------------");
			//System.out.println("il y a en mémoire : " + dicoSock);
			//System.out.println("le socket a pour valeur : " + socket);
			for (int i = 0; i < messdec.length; i++) {
				//System.out.println(messdec[i]);
			}
			for (int i = 0; i < vecSocket.size(); i++) {
				//System.out.println(" le vecteur : " + vecSocket.get(i));
			}
			//System.out.println("Fin------------------------------------------------------");
			
			

//			PrintWriter out = new PrintWriter(dicoSock.get(profilEnvoyeur).getOutputStream());
//			Thread t = new Thread(new Emission(out, mess, "ValEnvoiMess",this));	
//			t.start();
//			
//			out = new PrintWriter(dicoSock.get(profilRec).getOutputStream());
//			Thread t1 = new Thread(new Emission(out, mess, "ValEnvoiMess",this));	//EnvoiMess
//			t1.start();
			
//			int j = vecSocket.size()-1;
//			while(j-1 > (vecSocket.size()-4)){// soit j-2
//				//System.out.println("test avec J");
//				PrintWriter out = new PrintWriter(vecSocket.get(j).getOutputStream());
//				Thread t = new Thread(new Emission(out, mess, "EnvoiMess",this));	
//				t.start();
//				j--;
//			}
			
			for (int i = 0; i < vecSocket.size(); i++) {
				if(vecSocket.get(i) == socket){
				PrintWriter out = new PrintWriter(vecSocket.get(i).getOutputStream());
				Thread t = new Thread(new Emission(out, mess, "EnvoiMess",this));	
				t.start();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
//      try {
//      
//      message = in.readLine();
//      //System.out.println(login+" : "+message);
//      controleur.setMessage(message);
//      
//      if(message!= null || message != ""){
//      	Vector<Socket> vec = controleur.getVecOut();
//      	//System.out.println(vec);	
//          for(int i = 0; i< vec.size();i++)
//          {
//          	PrintWriter out = new PrintWriter(vec.get(i).getOutputStream());
//          	Thread t4 = new Thread(new Emission(out, message));
//              t4.start();	    
//              }  
//          }
//       
//      } catch (IOException e) {
//           
//          e.printStackTrace();
//      }
		
		
	}
	
	public void changerStatut(String infos, Socket socket){
		PrintWriter out = null;
		try {
			out = new PrintWriter(socket.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		String infosDec[] = decoupe(infos);
		//0 = profil
		//1 = nouveau statut
		getComptes().get(infosDec[0]).setStatut(Integer.valueOf(infosDec[1]));
		//System.out.println("statut actuel : " + getComptes().get(infosDec[0]).getStatut() + " demandé : " + infosDec[1]);
		Thread t = new Thread(new Emission(out, "Statut modifié", "statutChg",this));
		t.start();	
	}
	
	public HashMap<String, Socket> getVecSock() {
		return dicoSock;
	}
	public void setVecSock(HashMap<String, Socket> dicoSock) {
		this.dicoSock = dicoSock;
	}
	
}
